package com.zonski.jbots.desktop.applet;

import com.zonski.jbots.desktop.client.DesktopDevice;
import com.zonski.jbots.engine.Device;

import java.applet.Applet;
import java.applet.AudioClip;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;

/**
 * Created by IntelliJ IDEA.
 * User: Chris Glover
 * Date: Oct 28, 2003
 * Time: 12:42:01 PM
 * To change this template use Options | File Templates.
 */
public class AppletDevice extends DesktopDevice
{
    private Applet applet;
    private String soundPath;
    private String soundExt;
    private HashMap clips;
    private SoundRunner soundRunner;
    private Thread soundRunnerThread;

    public AppletDevice(Applet applet, String soundPath, String soundExt)
    {
        this.applet = applet;
        this.soundPath = soundPath;
        this.soundExt = soundExt;
        this.clips = new HashMap();
    }

    public void play(String name, int times)
    {
        if( this.soundRunner == null )
        {
            this.soundRunner = new SoundRunner();
            this.soundRunnerThread = new Thread( this.soundRunner );
            this.soundRunnerThread.start();
        }
        this.soundRunner.addPlayCommand( new PlayCommand( name, times ) );
    }

    public void stopAll()
    {
        if( this.soundRunner != null )
        {
            this.soundRunner.running = false;
        }
        Iterator iterator = this.clips.values().iterator();
        while(iterator.hasNext())
        {
            AudioClipInfo clip = (AudioClipInfo)iterator.next();
            clip.getClip().stop();
        }
    }

    private class AudioClipInfo
    {
        private AudioClip clip;
        private long lastPlayed;

        public AudioClipInfo(AudioClip clip)
        {
            this.clip = clip;
            this.lastPlayed = Long.MIN_VALUE;
        }

        public AudioClip getClip()
        {
            return this.clip;
        }

        public long getLastPlayed()
        {
            return this.lastPlayed;
        }

        public void setLastPlayed(long lastPlayed)
        {
            this.lastPlayed = lastPlayed;
        }
    }

    private class PlayCommand
    {
        private String name;
        private int times;
        public PlayCommand( String name, int times)
        {
            this.name = name;
            this.times = times;
        }
    }

    private class SoundRunner implements Runnable
    {
        private Vector playCommands;
        private boolean waiting;
        private boolean running;

        public SoundRunner()
        {
            this.playCommands = new Vector();
        }

        private void addPlayCommand( PlayCommand playCommand )
        {
            synchronized( this )
            {
                if( this.playCommands.size() > 20 )
                {
                    System.out.println("warning, switching player");
                    // something's wrong, drop waiting sounds
                    AppletDevice.this.soundRunnerThread.stop();
                    AppletDevice.this.soundRunner = null;
                    for( int i=0; i<this.playCommands.size(); i++)
                    {
                        PlayCommand pc = (PlayCommand) this.playCommands.elementAt( i );
                        AppletDevice.this.play( pc.name,  pc.times );
                    }
                }
                else
                {
                    this.playCommands.addElement( playCommand );
                    if( this.waiting )
                    {
                        this.notify();
                        this.waiting = false;
                    }
                }
            }
        }

        public void run()
        {
            this.running = true;

            while( this.running )
            {
                PlayCommand playCommand;
                synchronized( this )
                {

                    if( this.playCommands.size() == 0 )
                    {
                        try
                        {
                            this.waiting = true;
                            this.wait();
                        }
                        catch( InterruptedException ex )
                        {
                            ex.printStackTrace();
                        }
                    }
                    if( this.playCommands.size() > 0 )
                    {
                        playCommand = (PlayCommand) this.playCommands.remove( 0 );
                    }
                    else
                    {
                        playCommand = null;
                    }
                }
                if( playCommand != null )
                {
                    String name = playCommand.name;
                    int times = playCommand.times;
                    try
                    {
                        AudioClipInfo clip;
                        clip = (AudioClipInfo)AppletDevice.this.clips.get(name);
                        if(clip == null)
                        {
                            String path = AppletDevice.this.soundPath+name+AppletDevice.this.soundExt;
                            //URL url = this.getClass().getClassLoader().getResource(path);
                            //System.out.println(path+"=>"+url);
                            URL url = AppletDevice.this.applet.getCodeBase();
                            if(url != null)
                            {
                                clip = new AudioClipInfo(applet.getAudioClip(url, path));
                                AppletDevice.this.clips.put(name, clip);
                            }
                        }
                        if(clip != null)
                        {
                            if(times == Device.LOOP)
                            {
                                clip.getClip().loop();
                            }else{
                                long now = System.currentTimeMillis();
                                if(clip.getLastPlayed() < now - 500)
                                {
                                    // TODO : only ever will play once, regardless of the number of times specified
                                    clip.setLastPlayed(now);
                                    clip.getClip().play();
                                }
                            }
                        }
                    }catch(Exception ex){
                        System.err.println("error playing sound "+name);
                        ex.printStackTrace();
                    }
                }
            }
        }
    }
}
